package org.bdware.irp.irpserver;

import com.google.gson.Gson;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.ssl.SslHandler;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import org.apache.log4j.Logger;
import org.bdware.irp.irplib.core.IrpMessage;
import org.bdware.irp.irplib.core.IrpMessageCode;
import org.bdware.irp.irplib.core.IrpResponse;

import java.util.HashMap;

@ChannelHandler.Sharable
public class NettyServerHandler extends SimpleChannelInboundHandler<IrpMessage> {
    static Logger logger = Logger.getLogger(NettyServerHandler.class);
    protected IrpRequestHandler requestHandler;
    //HashMap<Integer, PushFileStream> clientMap = new HashMap<>();
    private int streamPushInterval = 500;

    public NettyServerHandler(IrpRequestHandler irpHandler) {
        this.requestHandler = irpHandler;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, IrpMessage msg) {
        logger.debug("receive a message: " + new Gson().toJson(msg.header));
        if (msg.header == null) {
//            logger.info("Invalid message, header: ");
            replyStringWithStatus(ctx, msg, "invalid request", IrpMessageCode.RC_ERROR);
            return;
        }

        //put the verify process in the server handler

        IrpMessage response = requestHandler.onRequest(msg);
        if(response != null){
            response.envelope.requestId = msg.envelope.requestId;
            logger.debug("return the response: " + response.toString());
            sendResponse(ctx,response);
        } else{
            defaultHandler(ctx,msg);
        }
    }

/*    private void sendResponseUsingStream(ChannelHandlerContext ctx, IrpMessage request) {
        PushFileStream pfs = new PushFileStream(ctx,request);
        pfs.start();
        clientMap.put(request.requestID,pfs);
    }*/

/*    @Override
    public void channelActive(ChannelHandlerContext ctx) {
//        logger.debug("channel active");
        if (ctx.pipeline().get(SslHandler.class) != null)
            ctx.pipeline().get(SslHandler.class).handshakeFuture().addListener(
                    (GenericFutureListener<Future<Channel>>) future -> {
                        if (future.isSuccess()) {
                            logger.info("TLS connection established");
                            SSLSession ss = ctx.pipeline().get(SslHandler.class).engine().getSession();
                            if (GlobalCertifications.needAuthentication) {
                                X509Certificate cert = ss.getPeerCertificateChain()[0];
                                String info;
                                // 获得公钥编码
                                info = new String(cert.getPublicKey().getEncoded());
                                logger.debug("PublicKey:" + info);
                                // 获得证书主体信息
                                info = cert.getSubjectDN().getName();
                                logger.debug("Certification Owner:" + info);
                                // 获得证书颁发者信息
                                info = cert.getIssuerDN().getName();
                                logger.debug("Certification Issuer:" + info);
                                // 获得证书签名算法名称
                                info = cert.getSigAlgName();
                                logger.debug("Sign Algorithm:" + info);
                            }
                        } else {
                            logger.info("TLS connection established failed");
                        }
                    });
    }*/

    public void defaultHandler(ChannelHandlerContext ctx, IrpMessage request) {
        replyStringWithStatus(ctx, request, "Unsupported Operation!", IrpMessageCode.RC_ERROR);
    }

    protected void replyStringWithStatus(ChannelHandlerContext ctx, IrpMessage request, String str, int responseCode) {
        IrpMessage response = IrpResponse.newErrorResponse(request.header.opCode, responseCode, str);
        response.envelope.requestId = request.envelope.requestId;
        sendResponse(ctx, response);
    }

    public void sendResponse(ChannelHandlerContext ctx, IrpMessage response) {
/*        if (response.header.isCertified()) {
            try {
                CryptoUtils.signDoipMessage(response);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }*/
        ctx.writeAndFlush(response);
    }

/*    private class PushFileStream extends Thread{
        ChannelHandlerContext ctx;
        IrpMessage request;
        boolean running = true;

        PushFileStream(ChannelHandlerContext ctx, IrpMessage msg){
            this.ctx = ctx;
            this.request = msg;
        }
        @Override
        public void run() {
            while(running){
                IrpMessage resp = requestHandler.onRequest(request);
                if(!ctx.channel().isActive()){
                    logger.warn("channel inactive");
                    return;
                }
                sendResponse(ctx,resp);
                try {
                    sleep(streamPushInterval);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        public void tryToStop(){
            running = false;
        }
    }

    private void stopStream(ChannelHandlerContext ctx, IrpMessage msg){
        logger.info("stop stream: ");
        clientMap.get(msg.requestID).tryToStop();
        clientMap.remove(msg.requestID);
        replyStringWithStatus(ctx, msg,"stopped", DoipResponseCode.Success);
    }*/
}
